/* Autostop
 *
 * Copyright (c) 2006 - 2007 Maciej Gajewski, Grzegorz Latarowski
 * http://code.google.com/p/autostop-automaty-drogowe
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
 */

///@file analyzer.h Main type definitions and public functions of the Analyzer library

#ifndef AUTOSTOP_ANALYZER_H
#define AUTOSTOP_ANALYZER_H

#include <stdint.h>	// uses uint8_t
#include <stdio.h>	// uses FILE

// STL
#include <list>
#include <vector>
using namespace std;




//////////////////////////////////////////////////////////////////
// IMAGE
//////////////////////////////////////////////////////////////////

///@defgroup imagemanipulation Image and mage manipulation
///@{

// TYPES

/// Data type used for storing pixel value
typedef uint8_t pixel_t;

/// Image struct - holds data for image.
/// Image is an aray of pixel_t values, ordered by rows, from top-left pixel.
/// Use image_pixel macro to access individual pixels
 struct image_t{
	int	width;					///< image width 
	int height;					///< image height
	pixel_t	pixels[0];			///< pixel data
} ;

/// Image pointer
typedef image_t*	pimage_t;

/// Map struct
/// Map is similar to image, but contains int values instead of pixels.
/// Use map_pixel to access indivodual values.
struct map_t{
	int	width;					///< map width 
	int height;					///< map height
	int	pixels[0];				///< pixel data
} ;

/// Map pointer
typedef map_t*	pmap_t;


/// macro wich expands into 'for' statement, iterating through image pixels.
///\warning in C code enclose whole statement in braces!
///@param ppixel index varibale name - will be declared as pointer to apixel_t
///@param pimage pointer to image data (type: pimage_t)
#define foreach_pixel( ppixel, pimage ) \
	pixel_t* ppixel; \
	pixel_t* __last_pointer = pimage->pixels + pimage->width * pimage->height; \
	for( ppixel = pimage->pixels; \
		ppixel != __last_pointer; \
		++ ppixel )

/// Macro providing access to single image pixel
#define image_pixel( pimage, x, y ) (pimage)->pixels[ (pimage)->width * (y) + (x) ]

/// Macro providing access to single  map pixel
#define map_pixel( pmap, x, y ) (pmap)->pixels[ (pmap)->width * (y) + (x) ]

// FUCNTIONS

/// Alocates image data and initializes pixels with zeroes
pimage_t create_image( int width, int height );

/// Frees allocated image
void free_image( pimage_t pimage );

/// Creates new image as copy of source image
pimage_t create_image_copy( const pimage_t psource );

/// Creates new map and initializes it with 0
pmap_t create_map( int width, int height );

/// Frees map struct
void free_map( pmap_t pmap );

/// Loads image from stream
pimage_t load_image( FILE* stream );

/// Saves image to file
int save_image( FILE* stream, pimage_t pimage );

///@}

//////////////////////////////////////////////////////////////////
// PROCESS
//////////////////////////////////////////////////////////////////

///@defgroup processmanipulation Analyze process
///@{

// CONSTANT

#define PRECISION_BITS		16				///< Number of bits used as floating-point part of calculated data
#define MAX_GROUPS			100				///< Max groups processed in image
#define MAX_OBJECTS			100				///< Max observed ojects
#define MAX_POINTS			2048			///< Max points in object movement data

// TYPES

// Proces parameters
struct process_params_t{
	double		background_factor;			///< background update factor, per millisecond of difference
	pixel_t		foreground_treshold;		///< Forground/background treshold
	int			segmentation_scale_log;		///< Segmentation scale log (real scale is 2^log)
	pixel_t		segment_treshold;			///< treshold for pixel on segmented image to be treated as 'active'
	int			max_group_size;				///< max acceptable group size [pixels]
	int 		min_group_size;				///< min acceptable group size [pixels]
	int 		max_group_distance;			///< max distabce between group (metric 1) to consider same object across frames[px/s]
	uint64_t	object_timeout;				///< object timeout, in ms 
} ;

/// Group info
struct group_t{
	// group geometry
	double	mx;		///< Mean x
	double	my;		///< Mean y
	int		minx;	///< Minimum X
	int		miny;	///< Minimum Y
	int		maxx;	///< Maximum X
	int		maxy;	///< Maximum Y

	// other info
	int		value;	///< Total group value (sum of all pixel's values )

	// counters
	int		pixels;	///< numbner of pixels belonging to group
	int 	xsum;	///< sum of group pixels x-coords
	int 	ysum;	///< sum of group pixels y-coords
	
} ;

/// Observed object point
struct object_point_t{
	int x;
	int y;
	int marker;				//!< distance marker area (or -1 for none )
	int shutter;			//!< shutter area
	uint64_t timestamp;		//!< timestamp
};

/// Moving object data
struct object_t {
	// observation history
	list<object_point_t>	points;		///< Observed points data

	// list head
	uint64_t	marker01Time;					///< Time of passing from marker 0 to 1, 0 for none
	uint64_t	marker12Time;					///< Time of passing from marker 1 to 2, 0 for none
	uint64_t	shutterTime;					//!< Shutter trigger time, 0 for none
	uint64_t	lastSeenTime;					//!< Where object was last seen - to remove tmouted objects
	double		speed;							///< Claculated speed [m/s], or 0.0 for none
} ;

/// Object pointer
typedef object_t*	pobject_t;
	
/// Process struct - stores state of entire process.
///\warning Do NOT modify its fields once process has started!
struct process_t {
	// static params
	process_params_t	params;					///< process params
	int					debug_draw;				///< debug: draw object on frame

	// dynamic process data
	pimage_t			pbackground;			///< background image
	int					processed_frames;		///< Processed frame counter
	uint64_t			last_frame_time;		///< Timestamp of last processed frame
	pimage_t			psegmented;				///< Segmented image

	// frame specific data
	vector<group_t>		groups;					///< groups array. may be huge
	
	/// groupmap - group indexes of each pixel. pixels arranged in rows
	/// -1 - no group, 0+ - group index. The array is initialized during scanning
	pmap_t				pgroupmap;

	// observed objects
	list<object_t>		objects;				///< observed objects data

	// distance markers
	int reference_distance;						///< Reference distance between first two markers [mm]
	pimage_t pdistance_markers;					///< Distance m,arkers map - set by user, freed by free_process!
	
	// shutter image
	pimage_t pshutter_markers;					///< Shutter marhjers image
	
	// region of interest
	pimage_t pROI;								///< Region of interest map - set by user, freed with process!

	// cached calculated data (totally internal)
	int	 				_int_background_factor;	///< background factor (in 2^-PRECISION_BITS)
};

/// Process pointer
typedef process_t*	pprocess_t;

// FUNCTIONS

/// Creates and initializes process
pprocess_t create_process();

/// Frees process
void free_process( pprocess_t pprocess );

/// Adds incoming image into process
void add_frame( pprocess_t pprocess, pimage_t pimage, uint64_t timestamp );

/// Adds incoming pre-processed frame to process
void add_segmented_frame( pprocess_t pprocess, pimage_t psegmented, uint64_t timestamp );

///@}


#endif /* AUTOSTOP_ANALYZER_H */

// eof 

